#pragma once
#include "IGameState.h"
#include "../SGD Wrappers/SGD_Handle.h"
#include "AnimationSystem.h"
#include "Emitter.h"

class Player;
class Goblin;
class Ogre;
class GameObject;
class MovingObject;
class ObjectManager;
class StaticObject;
class TileSystem;
class ParticleSystem;
class Portal;
class Game;
class Augment;
class Dash;
class BackDash;
class Slide;

enum class Levels { NO_CHANGE = -1, BASE, FOREST, CAVE, CASTLE, VOLCANO };
enum ObjBuckets {PORTAL_BUCKET, OBJ_BUCKET, PLAYER_BUCKET, ENEMY_BUCKET, PLAYER_BULLET_BUCKET, ENEMY_BULLET_BUCKET,AUGMENT_BUCKET};

#include "../SGD Wrappers/SGD_Declarations.h"
/**************************************************************/
// GameplayState class
//	- handles the GamePlay
//	- SINGLETON (statically allocated, not dynamic)
class GameplayState : public IGameState
{


public:
	/**********************************************************/
	// Singleton Accessor
	static GameplayState* GetInstance(void);


	/**********************************************************/
	// IGameState Interface:
	virtual void	Enter(void)				override;	// load resources
	virtual void	Exit(void)				override;	// unload resources

	virtual bool	Input(void)				override;	// handle user input
	virtual void	Update(float elapsedTime)	override;	// update entites
	virtual void	Render(void)				override;	// render entities / menu
	virtual void	HUD(void);
	void HUDCoolDowns(float cd, float currCD, SGD::HTexture image, SGD::Rectangle position);
	bool CheckCharacterCollision(SGD::Rectangle pastRect, SGD::Rectangle currRect, SGD::Rectangle otherRect);

	bool left, top, right, bottom;
	float sizeX;
	float sizeY;
	float movedX, movedY;

	//Factory Methods
	GameObject* CreatePlayer(SGD::Point position, string emitterName = "");
	GameObject* CreateProjectile(MovingObject * owner, float rotation, bool useFacing = true, string emitterName = "");
	GameObject* CreateGoblin(SGD::Point pos, string emitterName = "");
	GameObject* CreateOgre(SGD::Point pos, string emitterName = "");
	GameObject* CreateKnight(SGD::Point pos, string emitterName = "");
	GameObject* CreateBat(SGD::Point pos, bool vampire = false, string emitterName = "");
	GameObject* CreateElf(SGD::Point pos, string emitterName = "");
	GameObject* CreateArcher(SGD::Point pos, string emitterName = "");
	GameObject* CreateSpider(SGD::Point pos, string emitterName = "");
	GameObject* CreateVampire(SGD::Point pos, string emitterName = "");
	GameObject* CreateGiantSpider(SGD::Point pos, string emitterName = "");
	GameObject* CreateDragon(SGD::Point pos, string emitterName = "");
	GameObject* CreateHealthPickup(SGD::Point pos, string emitterName = "");
	GameObject* CreateShieldPickup(SGD::Point pos, string emitterName = "");
	GameObject* CreateAugmentTable(SGD::Point pos, int tabletype, string emitterName = "");
	GameObject* CreateLadder(SGD::Point pos, string emitterName = "");
	GameObject* CreateStairs(SGD::Point pos, string emitterName = "");


	//GameObject* CreateBoss  (void);
	GameObject* CreateAugment(SGD::Point pos, std::string name, string emitterName = "");
	GameObject* CreatePortal(int level, SGD::Point position, string emitterName = "");
	GameObject* CreatePortal(SGD::Point WarpLoc, SGD::Point position, string emitterName = "");
	GameObject* CreatePortal(SGD::Point position, string emitterName = "");
	Augment * RandomizeAugment();
	GameObject *ReturnObject(unsigned int bucket, int index);

	void	SetLevel(int level);


	Player* GetPlayer(void) { return player; }
	int		GetCurrLevel(void) const { return currLevel; }
	int		GetMapIndex(void) const { return mapIndex; }
	SGD::HTexture GetBulletImage() const { return bulletImage; }
	SGD::HTexture ladderImage = SGD::INVALID_HANDLE;
	SGD::HTexture vineImage = SGD::INVALID_HANDLE;
	SGD::HTexture stairImage = SGD::INVALID_HANDLE;
	SGD::HTexture shield = SGD::INVALID_HANDLE;

	//Emitter* GetEmitter() const { return emitter1; }

	void LoadUCC(void);
	void SetDisplayUCC(bool ducc) { displayUCC = ducc; }

	void LoadPlayerFile(string file);
	void SavePlayerFile(string file);

	void PauseOn() { 
		if (m_bPaused)
			prevPaused = true;
		else
			prevPaused = false;
		m_bPaused = true; }
	void PauseOff() { 
		if(!prevPaused)
			m_bPaused = prevPaused = false; }

protected:
	/**********************************************************/
	// SINGLETON!
	GameplayState(void) = default;
	virtual ~GameplayState(void) = default;

	GameplayState(const GameplayState&) = delete;
	GameplayState& operator= (const GameplayState&) = delete;
	/**********************************************************/
	TileSystem* TS = nullptr;

	AnimationSystem* animSys = nullptr;
	bool animationsLoaded = false;
	
	ParticleSystem* particleSystem = nullptr;

	SGD::AudioManager* pAudio = nullptr;
	Game* theGame = nullptr;

	//ObjectManager 
	ObjectManager* m_pObjects = nullptr;
	Player * player = nullptr;

	
//	GameObject * arcAug = nullptr;
//	GameObject* dashAug = nullptr;
//	GameObject* DjumpAug = nullptr;
	//Pause
	bool m_bPaused = false;
	bool prevPaused = false;
	bool htpMenuIsOpen = false;
	int m_nCursor = 0;
	int gameoverCursor = 0;
	//Audio Handles for Volume Control
	SGD::HAudio		m_AOptionsVolume = SGD::INVALID_HANDLE;
	SGD::HAudio		m_AOptionsVolume2 = SGD::INVALID_HANDLE;

	//Portals
	GameObject* basePortal = nullptr;
	GameObject* forestPortal = nullptr;
	int currLevel;
	int mapIndex = 0;
	int levelOne = 0;
	int levelTwo = 0;
	int levelThree = 0;
	int levelFour = 0;
	
	bool displayUCC;
	vector<std::string> uccList;

	bool playerHasLoaded = false;

	/**********************************************************/
	// Event & Message Managers
	SGD::EventManager*		m_pEvents = nullptr;
	SGD::MessageManager*	m_pMessages = nullptr;

	//*******************************************************************
	// Message Callback Procedure
	static	void	MessageProc(const SGD::Message* pMsg);

	//Camera Coordinates
	SGD::Point camPosition;

	//final level should be 4
	int finalLevel = 4;

	//The first time the player defeats the final boss this flag will be turned to true
	//If it is false then the VictoryState will display and return the player to the main menu
	bool gameComplete = false;

	Dash* dashAug = nullptr;
	BackDash* bdashAug = nullptr;
	Slide* slideAug = nullptr;

	bool initLoad = false;

	SGD::HTexture forestBackground = SGD::INVALID_HANDLE;
	SGD::HTexture caveBackground = SGD::INVALID_HANDLE;
	SGD::HTexture castleBackground = SGD::INVALID_HANDLE;
	SGD::HTexture volcanoBackground = SGD::INVALID_HANDLE;

	SGD::HTexture bulletImage = SGD::INVALID_HANDLE;
	SGD::HTexture hudImage = SGD::INVALID_HANDLE;
	SGD::HTexture dpad = SGD::INVALID_HANDLE;

	Emitter* emitter1 = nullptr;

	SGD::HTexture	m_hOptionsBar = SGD::INVALID_HANDLE;
	SGD::HAudio getPickUp = SGD::INVALID_HANDLE;
	SGD::HTexture explImage = SGD::INVALID_HANDLE;
};

struct explosion
{
	SGD::HTexture m_hImage = SGD::INVALID_HANDLE;
	SGD::Point position = { 0, 0 };
};